package auth

import (
	"context"
	"fmt"
	"github.com/gogf/gf/v2/errors/gcode"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/net/ghttp"
	"github.com/gogf/gf/v2/util/gconv"
	"github.com/gogf/gf/v2/util/gutil"
	"strconv"
	"time"
	v1 "zuhao-seucre/api/auth/v1"
	"zuhao-seucre/internal/boot/cache"
	"zuhao-seucre/internal/common/model"
	"zuhao-seucre/internal/consts"
	"zuhao-seucre/internal/dao"
	"zuhao-seucre/internal/model/entity"
	"zuhao-seucre/internal/service"
	utils "zuhao-seucre/utility"
	"zuhao-seucre/utility/captcha"
	"zuhao-seucre/utility/cryptox"
	"zuhao-seucre/utility/netx"
)

func (c *ControllerV1) Login(ctx context.Context, req *v1.LoginReq) (res *v1.LoginRes, err error) {

	accountLoginSecurity, err := service.SysConfig().GetAccountLoginSecurity(ctx)
	// 判断是否有开启登录验证码校验
	if accountLoginSecurity.UseCaptcha && !captcha.Verify(req.Cid, req.Captcha) {
		err = gerror.NewCode(gcode.CodeNil, "验证码验证失败")
		return
	}
	clientIp := getIpAndRegion(ctx)
	originPwd, err := cryptox.DefaultRsaDecrypt(ctx, req.Password, true)
	if err != nil {
		err = gerror.NewCode(gcode.CodeNil, "解密密码错误")
		return
	}

	// 查询用户
	var userInfo *entity.TSysAccount
	err = dao.TSysAccount.Ctx(ctx).Where(dao.TSysAccount.Columns().Username, req.Username).Scan(&userInfo)
	if gutil.IsEmpty(userInfo) || err != nil {
		err = gerror.NewCode(gcode.CodeNil, "用户不存在")
		return
	}
	failCountKey := fmt.Sprintf("account:login:failcount:%s", req.Username)
	nowFailCount, _ := cache.Instance().Get(ctx, failCountKey)
	count := nowFailCount.Int()

	loginFailCount := accountLoginSecurity.LoginFailCount
	loginFailMin := accountLoginSecurity.LoginFailMin

	if count > loginFailCount {
		err = gerror.NewCodef(gcode.CodeNil, "登录失败超过%d次, 请%d分钟后再试", count, loginFailMin)
		return
	}

	if err != nil || !cryptox.CheckPwdHash(originPwd, userInfo.Password) {
		count++
		cache.Instance().Set(ctx, failCountKey, strconv.Itoa(count), time.Minute*time.Duration(loginFailMin))
		err = gerror.NewCodef(gcode.CodeNil, "用户名或密码错误【当前登录失败%d次】", count)
		return
	}

	if !utils.CheckAccountPasswordLever(originPwd) {
		err = gerror.NewCode(gcode.New(401, "您的密码安全等级较低，请修改后重新登录", nil))
		return
	}

	if userInfo.Status != 1 {
		err = gerror.NewCodef(gcode.CodeNil, "该账号不可用")
		return
	}

	// 生成对应的token
	accessToken, refreshToken, err := service.Token().CreateToken(ctx, &model.UserModel{
		UserId:   userInfo.Id,
		Username: userInfo.Username,
	})

	res = &v1.LoginRes{
		Token:         accessToken,
		RefreshToken:  refreshToken,
		LastLoginIp:   clientIp,
		LastLoginTime: userInfo.LastLoginTime,
		Username:      userInfo.Username,
		Name:          userInfo.Name,
		Otp:           gconv.String(consts.OtpStatusNone),
	}
	return
}

func getIpAndRegion(ctx context.Context) string {
	clientIp := ghttp.RequestFromCtx(ctx).GetClientIp()
	return fmt.Sprintf("%s %s", clientIp, netx.Ip2Region(clientIp))
}
